package com.molichuxing.services.util;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.comm.Protocol;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * OSS上传工具类
 *
 * @author dengc
 * @date 2018年10月17日
 *
 */
@Component
public class OSSUploadUtil {
    private static Logger logger = LoggerFactory.getLogger(OSSUploadUtil.class);

    //OSS的内或外网域名
    private static final String ENDPOINT = "oss-cn-hangzhou.aliyuncs.com";
    //OSS的密钥Access Key ID
    private static String ACCESS_KEY_ID = "LTAI4RkCb2XN8l3X";
    //OSS的密钥Access Key Secret
    private static String ACCESS_KEY_SECRET = "eQ6roVlpd7JSZ37mPmgQGiQ28yMO4A";
    //OSS的bucket名称
    @Value("${oss.bucketNameCommon}")
    private String BUCKET_NAME_COMMON;
    @Value("${oss.bucketNamePrivate}")
    private String BUCKET_NAME_PRIVATE;

    /**
     * 获取OSS客户端对象
     * @return ossClient
     */
    public static OSSClient getOSSClient(){

        // 创建ClientConfiguration实例，按照您的需要修改默认参数。
        ClientConfiguration conf = new ClientConfiguration();
        // 开启支持CNAME。CNAME是指将自定义域名绑定到存储空间上。
        conf.setSupportCname(true);
        // 设置OSSClient允许打开的最大HTTP连接数，默认为1024个。
        conf.setMaxConnections(200);
        // 设置Socket层传输数据的超时时间，默认为50000毫秒。
        conf.setSocketTimeout(10000);
        // 设置建立连接的超时时间，默认为50000毫秒。
        conf.setConnectionTimeout(10000);
        // 设置从连接池中获取连接的超时时间（单位：毫秒），默认不超时。
        conf.setConnectionRequestTimeout(1000);
        // 设置连接空闲超时时间。超时则关闭连接，默认为60000毫秒。
        conf.setIdleConnectionTime(10000);
        // 设置失败请求重试次数，默认为3次。
        conf.setMaxErrorRetry(5);
        // 设置是否支持将自定义域名作为Endpoint，默认支持。
        conf.setSupportCname(true);
        // 设置是否开启二级域名的访问方式，默认不开启。
        conf.setSLDEnabled(false);
        // 设置连接OSS所使用的协议（HTTP/HTTPS），默认为HTTP。
        conf.setProtocol(Protocol.HTTPS);
        // 设置用户代理，指HTTP的User-Agent头，默认为aliyun-sdk-java。
        conf.setUserAgent("aliyun-sdk-java");

        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, conf);

        return ossClient;
    }


    /**
     * 创建存储空间
     * @param ossClient  OSS连接
     * @param bucketName 存储空间
     * @return
     */
    public static String createBucketName(OSSClient ossClient,String bucketName){
        //存储空间
        final String bucketNames = bucketName;
        if(!ossClient.doesBucketExist(bucketName)){
            //创建存储空间
            Bucket bucket = ossClient.createBucket(bucketName);
            logger.info("创建存储空间成功");
            return bucket.getName();
        }
        return bucketNames;
    }

    /**
     * 删除存储空间buckName
     * @param ossClient  oss对象
     * @param bucketName  存储空间
     */
    public static void deleteBucket(OSSClient ossClient, String bucketName){
        ossClient.deleteBucket(bucketName);
        logger.info("删除" + bucketName + "Bucket成功");
    }

    /**
     * 创建模拟文件夹
     * @param ossClient oss连接
     * @param bucketName 存储空间
     * @param folder   模拟文件夹名如"molichuxing/"
     * @return  文件夹名
     */
    public static String createFolder(OSSClient ossClient, String bucketName, String folder){
        //文件夹名
        final String keySuffixWithSlash = folder;
        //判断文件夹是否存在，不存在则创建
        if(!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)){
            //创建文件夹
            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
            logger.info("创建文件夹成功");
            //得到文件夹名
            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
            String fileDir = object.getKey();
            return fileDir;
        }
        return keySuffixWithSlash;
    }

    /**
     * 根据key删除OSS服务器上的文件
     * @param ossClient  oss连接
     * @param bucketName  存储空间
     * @param folder  模拟文件夹名 如"molichuxing/"
     * @param key Bucket下的文件的路径名+文件名 如："upload/cake.jpg"
     */
    public static void deleteFile(OSSClient ossClient, String bucketName, String folder, String key){
        ossClient.deleteObject(bucketName, folder + key);
        logger.info("删除" + bucketName + "下的文件" + folder + key + "成功");
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public static String getContentType(String fileName){
        //文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if(".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if(".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if(".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
                || ".png".equalsIgnoreCase(fileExtension) ) {
            return "image/jpeg";
        }
        if(".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if(".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if(".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if(".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if(".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if(".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        if(".pdf".equalsIgnoreCase(fileExtension)) {
            return "application/pdf";
        }
        //默认返回类型
        return "image/jpeg";
    }
    /**
     * 获得url链接
     *
     * @param
     * @return
     */
    public static String getUrl(OSSClient ossClient, String bucketName, String fileName) {
        // 设置URL过期时间为10年 3600* 1000*24*365*10
        Date expiration = new Date(new Date().getTime() + 315368760000l);
        // 生成URL
        URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration);
        if (url != null) {
            return url.toString();
        }
        return "获取路径异常";
    }

    /**
     * 获得url链接/自定义过期时间（单位：毫秒）
     *
     * @param
     * @return
     */
    public static String getUrlExpireTime(String urlStr, long validity) {
        if (StringUtils.isBlank(urlStr)){
            return null;
        }
        OSSClient ossClient = OSSUploadUtil.getOSSClient();
        // Date expiration = new Date(new Date().getTime() + 36000 * 1000 * 24 * 365 * 10);
        String bucketName = null;
        if (urlStr.contains("moliv2dev.oss-cn-hangzhou.aliyuncs.com") || urlStr.contains("static-test.molichuxing.com")){
            bucketName = "moliv2dev";
        }else if (urlStr.contains("mlresources.oss-cn-hangzhou.aliyuncs.com") || urlStr.contains("pristatic.molichuxing.com")){
            bucketName = "mlresources";
        }else if (urlStr.contains("mlpublic.oss-cn-hangzhou.aliyuncs.com")
                || (urlStr.contains("static.molichuxing.com") && !urlStr.contains("pristatic.molichuxing.com"))){
            bucketName = "mlpublic";
        }else {
            bucketName = "moliv2private";
        }

        String fileName = null;
        if (urlStr.contains(".com/")){
            fileName = urlStr.substring(urlStr.indexOf(".com/")+5);
        }
        if (fileName.contains("?")){
            fileName = fileName.substring(0, fileName.indexOf("?"));
        }
        if(fileName.contains("%2F")){
            fileName = fileName.replaceAll("%2F", "/");
        }
        Date expiration = new Date(new Date().getTime() + validity); //过期时间
        // 生成URL
        URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration);
        if (url != null) {
            String str = url.toString();
            if (str.contains("moliv2dev.oss-cn-hangzhou.aliyuncs.com")){
                str = str.replace("moliv2dev.oss-cn-hangzhou.aliyuncs.com", "static-test.molichuxing.com");
            }else if(str.contains("mlpublic.oss-cn-hangzhou.aliyuncs.com")){
                str = str.replace("mlpublic.oss-cn-hangzhou.aliyuncs.com", "static.molichuxing.com");
            }else if(str.contains("mlresources.oss-cn-hangzhou.aliyuncs.com")){
                str = str.replace("mlresources.oss-cn-hangzhou.aliyuncs.com", "pristatic.molichuxing.com");
            }

            return str;
        }
        return "获取路径异常";
    }
    /**
     * 上传图片、文件至OSS
     * @param ossClient  oss连接
     * @param bucketName  存储空间
     * @param file 要上传的文件
     * @return String 返回的存储路径
     * */
    public static String uploadObjectOSS(OSSClient ossClient, String bucketName, File file, String folderStr) throws Exception{
        String urlStr = "";
        try {
            //如果folder不存在则创建
            OSSUploadUtil.createFolder(ossClient, bucketName, folderStr);
            // 以输入流的形式上传文件
            String folder = folderStr + new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/";
            // 文件名
            String fileName = file.getName();
            fileName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + fileName.substring(fileName.lastIndexOf("."));
            logger.info("上传到路径" + folder + fileName);
            //System.out.println("上传到路径" + folder + file);
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            // 指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            // 指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            // 指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            // 如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(getContentType(fileName));
            // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            //metadata.setContentDisposition("filename/filesize=" + file + "/" + fileSize + "Byte.");
            // 上传文件 (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(bucketName, folder + fileName, file, metadata);
            // 解析URL
            urlStr = getUrl(ossClient, bucketName, folder + fileName);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
            throw e;
        }finally {
            //关闭oss链接，一定要关闭!!
            ossClient.shutdown();
        }
        return urlStr;
    }

    /**
     * 上传方法 MultipartFile
     * @param file
     * @param type（1：图片等公共资源（公共），2：合同发票等私有资源（私有））
     * @return
     */
    public String uploadToOss(MultipartFile file, Integer type, String folder) throws Exception {
        //初始化OSSClient
        OSSClient ossClient = OSSUploadUtil.getOSSClient();
        //bucket
        String bucket = BUCKET_NAME_COMMON;
        if (2==type){
            bucket = BUCKET_NAME_PRIVATE;
        }
        if (StringUtils.isBlank(folder)){
            folder = "molichuxing";
        }
        //MultipartFile转换File
        String fileName = file.getOriginalFilename();
        String suffix = fileName.substring(fileName.lastIndexOf("."));

        File tempFile = File.createTempFile("temp", suffix);//创建临时文件
        try {
            FileUtils.copyInputStreamToFile(file.getInputStream(), tempFile);
            return OSSUploadUtil.uploadObjectOSS(ossClient, bucket, tempFile, folder+"/");
        }finally {
            tempFile.deleteOnExit(); //程序退出时删除临时文件
        }
    }

    /**
     * 上传方法 File
     * @param file
     * @param type（1：图片等公共资源（公共），2：合同发票等私有资源（私有））
     * @param folder（传字符串：contract：合同, invoice：发票 。。。）
     * @return
     */
    public String uploadToOss(File file, Integer type, String folder) throws Exception {
        //初始化OSSClient
        OSSClient ossClient = OSSUploadUtil.getOSSClient();
        String bucket = BUCKET_NAME_COMMON;
        if (2==type){
            bucket = BUCKET_NAME_PRIVATE;
        }
        if (StringUtils.isBlank(folder)){
            folder = "molichuxing";
        }
        String url = OSSUploadUtil.uploadObjectOSS(ossClient, bucket, file, folder+"/");
        //if (1==type){
        //删除公共Bucket里文件后缀名后面的多余参数，替换域名
			/*if (url.contains("?")){
				url = url.substring(0, url.indexOf("?"));
			}*/
        if (url.contains("moliv2dev.oss-cn-hangzhou.aliyuncs.com")){
            url = url.replace("moliv2dev.oss-cn-hangzhou.aliyuncs.com", "static-test.molichuxing.com");
        }else if(url.contains("mlpublic.oss-cn-hangzhou.aliyuncs.com")){
            url = url.replace("mlpublic.oss-cn-hangzhou.aliyuncs.com", "static.molichuxing.com");
        }else if(url.contains("mlresources.oss-cn-hangzhou.aliyuncs.com")){
            url = url.replace("mlresources.oss-cn-hangzhou.aliyuncs.com", "pristatic.molichuxing.com");
        }
        //}

        return url;
    }

}
